{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import (\n",
    "    \"flag\"\n",
    "    \"io/ioutil\"\n",
    "    \"log\"\n",
    "    \"os\"\n",
    "    \"path/filepath\"\n",
    "    \"strings\"\n",
    "    \"time\"\n",
    "    \"unicode\"\n",
    "    \"fmt\"\n",
    "    \"encoding/json\"\n",
    "\n",
    "    \"github.com/machinebox/sdk-go/facebox\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Connect to MachineBox"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To perform facial recognition, we are going to use MachineBox's FaceBox. If you haven't heard of MachineBox, [check them out](https://machinebox.io/)! They provide state of the art machine learning technology inside a Docker container which you can run, deploy and scale.\n",
    "\n",
    "Here we will assume that we have MachineBox's facebox running locally."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "faceboxClient := facebox.New(\"http://localhost:8080\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Train FaceBox to recognize a face"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are now going to walk over images of faces in a directory and provide these faces to facebox.  FaceBox will  learn how to recognize these faces in images.  The faces that we are going to use here are of someone that is probably familiar to most:\n",
    "\n",
    "trump1.jpg            |  trump2.jpg   |  trump3.jpg  \n",
    ":-------------------------:|:-------------------------:|:-------------------------:\n",
    "![](https://raw.githubusercontent.com/dwhitena/pach-machine-box/master/data/train/faces1/trump1.jpg)  |  ![](https://raw.githubusercontent.com/dwhitena/pach-machine-box/master/data/train/faces1/trump2.jpg) |  ![](https://raw.githubusercontent.com/dwhitena/pach-machine-box/master/data/train/faces1/trump3.jpg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "inDir := \"/home/dwhitena/go/src/github.com/dwhitena/pach-machine-box/data/train/faces1\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "ERROR",
     "evalue": "// warning: redefined identifier: err\n// warning: call to deferred function f.Close() returned [<nil>] values, expecting zero: %!v(MISSING)\n// warning: redefined identifier: err\n// warning: call to deferred function f.Close() returned [<nil>] values, expecting zero: %!v(MISSING)\n// warning: redefined identifier: err\n// warning: call to deferred function f.Close() returned [<nil>] values, expecting zero: %!v(MISSING)\n",
     "output_type": "error",
     "traceback": [
      "// warning: redefined identifier: err\n// warning: call to deferred function f.Close() returned [<nil>] values, expecting zero: %!v(MISSING)\n// warning: redefined identifier: err\n// warning: call to deferred function f.Close() returned [<nil>] values, expecting zero: %!v(MISSING)\n// warning: redefined identifier: err\n// warning: call to deferred function f.Close() returned [<nil>] values, expecting zero: %!v(MISSING)\n"
     ]
    }
   ],
   "source": [
    "// Walk over images in the training directory.\n",
    "if err := filepath.Walk(inDir, func(path string, info os.FileInfo, err error) error {\n",
    "\n",
    "    // Skip any directories.\n",
    "    if info.IsDir() {\n",
    "        return nil\n",
    "    }\n",
    "\n",
    "    // Open the training image file.\n",
    "    f, err := os.Open(filepath.Join(inDir, info.Name()))\n",
    "    if err != nil {\n",
    "        return err\n",
    "    }\n",
    "    defer f.Close()\n",
    "\n",
    "    // Teach FaceBox the input image.\n",
    "    if err := faceboxClient.Teach(f, info.Name(), \"trump\"); err != nil {\n",
    "        return err\n",
    "    }\n",
    "\n",
    "    return nil\n",
    "}); err != nil {\n",
    "    log.Println(err)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using the trained FaceBox to recognize a face"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have trained FaceBox to recognize our face of interest, we can try to identify this face in an image. For example, let's try to recognize this face in the following image:\n",
    "\n",
    "![](https://raw.githubusercontent.com/dwhitena/pach-machine-box/master/data/unidentified/image1.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let's create a struct that will allow us to unmarshal the JSON response from FaceBox.  This JSON response should include an indication that faces where detected along with labels of recognized faces and their locations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "// IdentifiedFaces includes information about the faces\n",
    "// identified in an image.\n",
    "type IdentifiedFaces struct {\n",
    "    Success    bool           `json:\"success\"`\n",
    "    FacesCount int            `json:\"facesCount\"`\n",
    "    Faces      []facebox.Face `json:\"faces\"`\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we can use the `Check()` method on the FaceBox client to check the image for recognized faces:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "ERROR",
     "evalue": "// warning: redefined identifier: err\n",
     "output_type": "error",
     "traceback": [
      "// warning: redefined identifier: err\n"
     ]
    }
   ],
   "source": [
    "// Open the input image.\n",
    "f, err := os.Open(\"/home/dwhitena/go/src/github.com/dwhitena/pach-machine-box/data/unidentified/image1.jpg\")\n",
    "if err != nil {\n",
    "    log.Println(err)\n",
    "}\n",
    "defer f.Close()\n",
    "\n",
    "// Teach FaceBox the input image.\n",
    "faces, err := faceboxClient.Check(f)\n",
    "if err != nil {\n",
    "    log.Println(err)\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we can output the detected face information:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "  \"Success\": true,\n",
       "  \"FacesCount\": 13,\n",
       "  \"Faces\": [\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 199,\n",
       "        \"Left\": 677,\n",
       "        \"Width\": 107,\n",
       "        \"Height\": 108\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 96,\n",
       "        \"Left\": 1808,\n",
       "        \"Width\": 89,\n",
       "        \"Height\": 90\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 163,\n",
       "        \"Left\": 509,\n",
       "        \"Width\": 108,\n",
       "        \"Height\": 108\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 186,\n",
       "        \"Left\": 2186,\n",
       "        \"Width\": 89,\n",
       "        \"Height\": 89\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 166,\n",
       "        \"Left\": 1638,\n",
       "        \"Width\": 90,\n",
       "        \"Height\": 89\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 116,\n",
       "        \"Left\": 1453,\n",
       "        \"Width\": 107,\n",
       "        \"Height\": 107\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 405,\n",
       "        \"Left\": 1131,\n",
       "        \"Width\": 89,\n",
       "        \"Height\": 89\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 206,\n",
       "        \"Left\": 1300,\n",
       "        \"Width\": 90,\n",
       "        \"Height\": 89\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 176,\n",
       "        \"Left\": 1957,\n",
       "        \"Width\": 90,\n",
       "        \"Height\": 89\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 495,\n",
       "        \"Left\": 1462,\n",
       "        \"Width\": 62,\n",
       "        \"Height\": 62\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 1158,\n",
       "        \"Left\": 2181,\n",
       "        \"Width\": 62,\n",
       "        \"Height\": 63\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 175,\n",
       "        \"Left\": 963,\n",
       "        \"Width\": 108,\n",
       "        \"Height\": 108\n",
       "      },\n",
       "      \"ID\": \"trump3.jpg\",\n",
       "      \"Name\": \"trump\",\n",
       "      \"Matched\": true\n",
       "    },\n",
       "    {\n",
       "      \"Rect\": {\n",
       "        \"Top\": 544,\n",
       "        \"Left\": 1647,\n",
       "        \"Width\": 75,\n",
       "        \"Height\": 75\n",
       "      },\n",
       "      \"ID\": \"\",\n",
       "      \"Name\": \"\",\n",
       "      \"Matched\": false\n",
       "    }\n",
       "  ]\n",
       "}\n"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "ename": "ERROR",
     "evalue": "// warning: redefined identifier: err\n",
     "output_type": "error",
     "traceback": [
      "// warning: redefined identifier: err\n"
     ]
    }
   ],
   "source": [
    "// Prepare the output.\n",
    "output := IdentifiedFaces{\n",
    "    Success:    true,\n",
    "    FacesCount: len(faces),\n",
    "    Faces:      faces,\n",
    "}\n",
    "\n",
    "// Marshal the output.\n",
    "outputData, err := json.MarshalIndent(output, \"\", \"  \")\n",
    "if err != nil {\n",
    "    return log.Println(err)\n",
    "}\n",
    "\n",
    "fmt.Println(string(outputData))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Go",
   "language": "go",
   "name": "gophernotes"
  },
  "language_info": {
   "codemirror_mode": "",
   "file_extension": ".go",
   "mimetype": "",
   "name": "go",
   "nbconvert_exporter": "",
   "pygments_lexer": "",
   "version": "go1.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
